﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace SCM.Common.Extensions
{
    /// <summary>
    /// 加密类型
    /// </summary>
    public enum SHA1TypeEnum
    {
        IsString = 0x1,
        IsFile = 0x2
    }

    /// <summary>
    /// 加密解密工具类
    /// </summary>
    public class EncryptHelper
    {
        /// <summary>
        /// 字符串SHA1加密
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string HashSha1String(string str, Encoding encod)
        {
            return HashString(encod.GetBytes(str), "sha1");
        }
        /// <summary>
        /// 字符串MD5加密
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string HashMD5String(string str, Encoding encod)
        {
            return HashString(encod.GetBytes(str), "md5");
        }
        /// <summary>
        /// byte数组MD5加密
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static string HashMD5Byte(byte[] buffer)
        {
            return HashString(buffer, "md5");
        }
        /// <summary>
        /// byte数组SHA1加密
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static string HashSha1Byte(byte[] buffer)
        {
            return HashString(buffer, "sha1");
        }
        /// <summary>
        /// SHA1加密
        /// </summary>
        /// <param name="str">字符串或者路径</param>
        /// <param name="ifo">类型</param>
        /// <returns></returns>
        public static string HashSha1String(string str, SHA1TypeEnum ifo)
        {
            if (ifo == SHA1TypeEnum.IsFile)
            {

                if (!File.Exists(str))
                    throw new Exception("文件不存在！");
                FileStream fs = new FileStream(str, FileMode.Open, FileAccess.Read);
                string str1 = HashData(fs, "md5");
                fs.Close();
                return str1;
            }
            else
            {
                return HashSha1String(str, Encoding.UTF8);
            }
        }
        /// <summary>
        /// MD5加密
        /// </summary>
        /// <param name="str">字符串或路径</param>
        /// <param name="ifo">类型</param>
        /// <returns></returns>
        public static string HashMD5String(string str, SHA1TypeEnum ifo = SHA1TypeEnum.IsString)
        {
            if (ifo == SHA1TypeEnum.IsFile)
            {
                if (!File.Exists(str))
                    throw new Exception("文件不存在！");
                FileStream fs = new FileStream(str, FileMode.Open, FileAccess.Read);
                string str1 = HashData(fs, "md5");
                fs.Close();
                return str1;
            }
            else
            {
                return HashMD5String(str, Encoding.UTF8);
            }
        }

        private static string HashString(byte[] b, string algName)
        {
            HashAlgorithm algorithm;
            if (algName == null)
            {
                throw new ArgumentNullException("algName 不能为 null");
            }
            if (string.Compare(algName, "sha1", true) == 0)
            {
                algorithm = SHA1.Create();
            }
            else
            {
                if (string.Compare(algName, "md5", true) != 0)
                {
                    throw new Exception("algName 只能使用 sha1 或 md5");
                }
                algorithm = MD5.Create();
            }
            byte[] retby = algorithm.ComputeHash(b);
            return BytesToHexString(retby);
        }
        private static string HashData(Stream stream, string algName)
        {
            HashAlgorithm algorithm;
            if (algName == null)
            {
                throw new ArgumentNullException("algName 不能为 null");
            }
            if (string.Compare(algName, "sha1", true) == 0)
            {
                algorithm = SHA1.Create();
            }
            else
            {
                if (string.Compare(algName, "md5", true) != 0)
                {
                    throw new Exception("algName 只能使用 sha1 或 md5");
                }
                algorithm = MD5.Create();
            }
            byte[] retby = algorithm.ComputeHash(stream);
            return BytesToHexString(retby);
        }
        protected static string BytesToHexString(byte[] b)
        {
            StringBuilder str = new StringBuilder(b.Length * 2);
            foreach (byte bt in b)
            {
                str.Append(ByteToHexString(bt));
            }
            return str.ToString();
        }
        protected static string ByteToHexString(byte by)
        {
            string str = by.ToString("X");
            if (str.Length < 2)
            {
                str = "0" + str;
            }
            return str;
        }
        /// <summary>
        /// 非对称加密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="publicstr">公钥</param>
        /// <returns></returns>
        public static string EncryptGetString(string str, string publicstr)
        {
            return Convert.ToBase64String(EncryptGetBytes(str, publicstr));
        }
        /// <summary>
        /// 非对称加密
        /// </summary>
        /// <param name="str"></param>
        ///<param name="publicstr">公钥</param>
        /// <returns></returns>
        public static byte[] EncryptGetBytes(string str, string publicstr)
        {
            return EncryptGetBytes(Encoding.Default.GetBytes(str), publicstr);
        }

        private static byte[] EncryptGetBytes(byte[] by, string publicstr)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
            rsa.FromXmlString(publicstr);
            return rsa.Encrypt(by, false);
        }
        /// <summary>
        /// 非对称解密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="Privatestr"></param>
        /// <returns></returns>
        public static string DecryptGetString(string str, string Privatestr)
        {
            return Encoding.Default.GetString(DecryptGetBytes(str, Privatestr));
        }
        private static byte[] DecryptGetBytes(string str, string Privatestr)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
            rsa.FromXmlString(Privatestr);
            return rsa.Decrypt(Convert.FromBase64String(str), false);
        }
        /// <summary>
        /// 获取公钥和私钥，下标0为公钥，下标1为私钥
        /// </summary>
        /// <returns></returns>
        public static string[] GetRSAkey()
        {
            string[] arr = new string[2];
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
            arr[0] = rsa.ToXmlString(false);
            arr[1] = rsa.ToXmlString(true);
            return arr;
        }
        private static byte[] Keys = { 0x01, 0x04, 0x02, 0x02, 0x03, 0x04, 0x04, 0xFF };
        /// <summary>
        /// DES加密字符串
        /// </summary>
        /// <param name="encryptString">待加密的字符串</param>
        /// <param name="encryptKey">加密密钥,要求为8位</param>
        /// <returns>加密成功返回加密后的字符串，失败返回源串</returns>
        public static string EncryptDES(string encryptString, string encryptKey, byte[] ivKey = null)
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
                byte[] rgbIV = ivKey == null ? Keys : ivKey;
                byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
                DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();
                using (MemoryStream mStream = new MemoryStream())
                {
                    CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                    cStream.Write(inputByteArray, 0, inputByteArray.Length);
                    cStream.FlushFinalBlock();
                    return Convert.ToBase64String(mStream.ToArray());
                }
            }
            catch
            {
                return encryptString;
            }
        }

        /// <summary>
        /// DES解密字符串
        /// </summary>
        /// <param name="decryptString">待解密的字符串</param>
        /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>
        /// <returns>解密成功返回解密后的字符串，失败返源串</returns>
        public static string DecryptDES(string decryptString, string decryptKey, byte[] ivKey = null)
        {
            try
            {
                byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 8));
                byte[] rgbIV = ivKey == null ? Keys : ivKey;
                byte[] inputByteArray = Convert.FromBase64String(decryptString);
                DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();
                using (MemoryStream mStream = new MemoryStream())
                {
                    CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);
                    cStream.Write(inputByteArray, 0, inputByteArray.Length);
                    cStream.FlushFinalBlock();
                    return Encoding.UTF8.GetString(mStream.ToArray());
                }
            }
            catch
            {
                return decryptString;
            }
        }
    }
}
